local M={}

local escape_char_map = {
  [ "\\" ] = "\\",
  [ "\"" ] = "\"",
  [ "\b" ] = "b",
  [ "\f" ] = "f",
  [ "\n" ] = "n",
  [ "\r" ] = "r",
  [ "\t" ] = "t",
}

local function escape_char(c)
  return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end


local function cmp(a,b)
    local tpa=type(a)
    local tpb=type(b)
    if tpa == tpb then return a<b end
    if tpa == "number" then return true end
    return false
end

local function tbl_iterator(tbl)
	local a = {}  
	for n in pairs(tbl) do  
		a[#a+1] = n  
	end  
	table.sort(a,cmp)
	local i = 0  
	return function()  
		i = i + 1  
		return a[i], tbl[a[i]]  
	end 
end

local function is_array(tbl)
    local n = #tbl
    local count=0
    for i in pairs(tbl) do  
        if type(i) ~= "number" then
            return false
        end
        if i > n then
            return false
        end 
        count=count+1
    end  
    return n==count
end

local function to_jsonstr(v)
    return '"' .. v:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end

local function encode_value(v)
    local tp=type(v)
    if tp == "table" then
        if is_array(v) then
           return M.json_encode_array(v)
        end
        return M.json_encode_table(v)
    end
    if tp == "string" then
        return to_jsonstr(v)
    end
    if tp == "boolean" then
        if v then
            return "true" 
        end
        return
    end
    return v
end

local function encode_key(k)
    return "\""..tostring(k).."\""
end

local function json_encode_table(json_table)
    if not json_table then
        return ""
    end
    local s
    for k, v in tbl_iterator(json_table) do
        k=encode_key(k)
        v=encode_value(v)
        if v then
            if s then
                s=s..", "..k..":"..v
            else
                s=k..":"..v
            end
        end
    end
    return "{ "..(s or "").." }"
end

local function json_encode_array(json_table)
    if not json_table then
        return ""
	end
    local s
    for k, v in pairs(json_table) do
        v=encode_value(v)
        if v then
            if s then
                s=s..", "..v 
            else
                s=v
            end
        end
    end
    return "[ "..(s or "").." ]"
end
M.json_encode_table=json_encode_table
return M